﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KeshaParser
{
    class Parser : BaseParser
    {
        private Stack<GrammarItem> stack;
        private GrammarTable table;

        public Parser(Scanner scanner)
        {
            this.scanner = scanner;
            this.table = new GrammarTable();
        }
     
        public bool Parse()
        {
            Reset();
            stack = new Stack<GrammarItem>();
            stack.Push(Token.CreateEofToken());
            stack.Push(table.GetStartSymbol());
            return ParseProgram();
        }

        private bool ParseProgram()
        {
            GrammarItem X = stack.Peek();
            GetNextToken();
            while ( !EofOnTop() )
            {
                Token a = currentToken;
                if (X.Equals(a))
                {
                    stack.Pop();
                    GetNextToken();
                }
                else if (X is Token)
                {
                    Console.WriteLine("Exit on X=" + (X as NonTerminal));
                    return false;
                }
                else if (table.LookUp(X as NonTerminal, a) == null)
                {
                    Console.WriteLine("Exit on X=" + (X as NonTerminal) + ", a=" + a);
                    return false;
                }
                else if (table.LookUp(X as NonTerminal, a) != null)
                {
                    Derivation d = table.LookUp(X as NonTerminal, a);
                    stack.Pop();

                    bool deriviedToEpsilon = ((d.Count == 1) &&
                                             (d[0] is NonTerminal) &&
                                             (d[0] as NonTerminal).IsEpsilon());

                    if (!deriviedToEpsilon)
                    {
                        for (int i = d.Count - 1; i >= 0; --i)
                        {
                            stack.Push(d[i]);
                        }
                    }
                }
                else
                {
                    throw new Exception("Code unreachable");
                }
                
                X = stack.Peek();

                Console.Write("Stack: ");
                foreach (var i in stack)
                {
                    Console.Write(i + " ");
                }
                Console.WriteLine();
            }

            return true;
        }

        private bool EofOnTop()
        {
            GrammarItem top = stack.Peek();
            Token token = top as Token;
            return (token != null) && (token.Type == TokenType.EOF);
        }
    }
}
